/* Turska Framework/UI library (Turs2)
 * Copyright 2003-2009 Jetro Lauha
 * All rights reserved.
 * Web: http://iki.fi/jetro/turska/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of EITHER:
 *   (1) The GNU Lesser General Public License as published by the Free
 *       Software Foundation; either version 2.1 of the License, or (at
 *       your option) any later version. The text of the GNU Lesser
 *       General Public License is included with this library in the
 *       file LICENSE-LGPL.txt.
 *   (2) The BSD-style license that is included with this library in
 *       the file LICENSE-BSD.txt.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
 * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
 *
 * $Id: T2IMGUIImageTextFieldStyle.cpp 131 2009-06-05 05:58:05Z jlauha $
 * $Revision: 131 $
 */

#include <assert.h>

#include "Turs2.h"


namespace turska
{

static REAL clamp(REAL value, REAL min, REAL max)
{
    return value < min ? min : (value > max ? max : value);
}

static REAL step(REAL value, REAL stepPosition)
{
    return value < stepPosition ? (REAL)0 : (REAL)1;
}

static REAL pulse(REAL value, REAL startPosition, REAL endPosition)
{
    return step(value, startPosition) - step(value, endPosition);
}

static REAL boxStep(REAL value, REAL slopeStart, REAL slopeEnd)
{
    REAL diff = slopeEnd - slopeStart;
    if (diff == 0)
        return step(value, slopeStart);
    return clamp((value - slopeStart) / diff, 0, 1);
}

static REAL boxPulse(REAL value, REAL upSlopeStart, REAL upSlopeEnd,
                     REAL downSlopeStart, REAL downSlopeEnd)
{
    return boxStep(value, upSlopeStart, upSlopeEnd) -
           boxStep(value, downSlopeStart, downSlopeEnd);
}


IMGUIImageTextFieldStyle::IMGUIImageTextFieldStyle(Font *font, Image *caretImage, Image *imageUp,
                                                   Image *imageHot, Image *imageActive) :
    mScale(1),
    mCaretImage(caretImage),
    mImageWidth(0), mImageHeight(0),
    mFont(font),
    mTextOffsetX(2), mTextOffsetY(0)
{
    mTextFieldColor.set(0xffffffff);
    mTextColor.set(0xffffffff);
    mCaretColor.set(0xffffffff);
    mImages[IMGUI_WS_DEFAULT] = imageUp;
    mImages[IMGUI_WS_HOT] = imageHot;
    mImages[IMGUI_WS_ACTIVE] = imageActive;
    mImages[IMGUI_WS_HOT_ACTIVE] = imageActive;
    Image *img = mImages[IMGUI_WS_DEFAULT];
    if (img == 0)
        img = mImages[IMGUI_WS_HOT];
    if (img == 0)
        img = mImages[IMGUI_WS_ACTIVE];
    //if (img == 0)
    //    img = mImages[IMGUI_WS_HOT_ACTIVE];
    if (img != 0)
    {
        mImageWidth = (UI32)img->getWidth();
        mImageHeight = (UI32)img->getHeight();
    }
    if (font)
        mTextOffsetX = (REAL)((I32)(font->getFontHeight() / 10));
}


bool IMGUIImageTextFieldStyle::isInside(const IMGUI &imgui, REAL x, REAL y,
                                        const Rectangle &area)
{
    const bool haveCustomArea = (area.width != 0 && area.height != 0);
    x -= area.x;
    y -= area.y;
    if (!haveCustomArea)
    {
        if (mImageWidth > 0 && mImageHeight > 0)
            return x >= 0 && y >= 0 &&
                   x < mImageWidth * mScale && y < mImageHeight * mScale;
    }
    return x >= 0 && y >= 0 && x < area.width && y < area.height;
}


bool IMGUIImageTextFieldStyle::isCharAllowed(UI32 character)
{
    // if no font given, allow any character
    return !mFont || mFont->hasCharacter(character);
}


Rectangle IMGUIImageTextFieldStyle::render(const IMGUI &imgui, I32 widgetState,
                                           REAL x, REAL y, REAL width, REAL height,
                                           const C8 *text)
{
    assert(widgetState >= 0 && widgetState < IMGUI_WS_COUNT);
    const bool renderingEnabled = imgui.isRenderingEnabled();
    Image *textFieldImage = mImages[widgetState];
    UI32 defaultFlags = IF_TRANSFORM | IF_SCALE | IF_COLOR | IF_ALPHA | IF_ALIGN_TOP_LEFT;
    const bool haveCustomArea = (width != 0 && height != 0);
    if (!haveCustomArea)
    {
        if (textFieldImage != 0)
        {
            if (renderingEnabled)
            {
                textFieldImage->setScale(mScale);
                textFieldImage->draw(IDM_NORMAL, defaultFlags, x, y, mTextFieldColor);
            }
            width = mScale * mImageWidth;
            height = mScale * mImageHeight;
        }
    } // !haveCustomArea
    Rectangle resultArea(x, y, width, height);

    // text itself
    if (renderingEnabled)
    {
        REAL bx = x + mTextOffsetX;
        REAL by = y + mTextOffsetY + textFieldImage->getHeight() * mScale / 2;
        if (mFont != 0)
            by -= mFont->getFontHeight(mScale) / 2;
        bx = (REAL)((I32)bx);
        by = (REAL)((I32)by);

        REAL width = 0;
        if (mFont != 0 && text != 0)
            width = mFont->drawString(bx, by, text, IF_ALIGN_TOP_LEFT,
                                      mScale, mTextColor);
        if (mCaretImage != 0 &&
            (imgui.getActiveKeyWidgetId() == imgui.getCurrentWidgetId()))
        {
            REAL caretX = bx + width, caretY = by;
            if (mFont != 0)
            {
                caretX += mFont->getCharacterSpacing() * mScale / 2;
                caretY += mFont->getFontHeight() * mScale / 2;
            }
            else
                caretY += height / 2;
            caretX -= mCaretImage->getWidth() * mScale / 3;
            I32 pulseTime = (imgui.getTime() - imgui.getLastKeyEventTime()) & 511;
            turska::Color color = mCaretColor;
            color.a = (UI8)(255 * (REAL(1) - boxPulse((REAL)pulseTime, 160, 256, 416, 512)));
            UI32 flags = IF_ALIGN_LEFT_VCENTER | IF_COLOR | IF_ALPHA;
            if (mScale == REAL(1))
            {
                caretX = (REAL)((I32)caretX);
                caretY = (REAL)((I32)caretY);
            }
            else
            {
                flags |= IF_TRANSFORM | IF_SCALE;
                mCaretImage->setScale(mScale);
            }
            mCaretImage->draw(mCaretImage->getDrawMode(), flags, caretX, caretY, color);
        }
    }

    return resultArea;
}


} // namespace turska
